//
// Created by tcj on 2022/7/14.
//

#include "timer.h"
/*
 * 定时器给每一个http链接设置一个过期时间，定期清理超过过期时间的链接，减少服务器的无效资源。提高服务器的运行效率。
 *
 * */
namespace tcj{
    void TimerManager::swapNode(size_t i, size_t j) {
        assert(i>=0 && i<time_array_.size());
        assert(j>=0 && j<time_array_.size());
        std::swap(time_array_[i],time_array_[j]);
        fd_pos_array_[time_array_[i].id] = j;
        fd_pos_array_[time_array_[j].id] = i;
    }


    void TimerManager::siftup(size_t i) {
        assert(i>=0 && i< time_array_.size());
        size_t j = (i-1)/2;
        while(j>=0){
            if(time_array_[j] < time_array_[i]) break;
            swapNode(i,j);
            i =j;
            j = (i-1)/2;
        }
    }

    bool TimerManager::sifydown(size_t index, size_t n) {
        assert(index>=0 && index<time_array_.size());
        assert(n>=0 && n<=time_array_.size());

        size_t i = index;
        size_t j = i*2+1;
        while(j<n){
            if(j+1<n && time_array_[j+1] <time_array_[j]) j++;
            if(time_array_[i] < time_array_[j]) break;
            swapNode(i,j);
            i = j;
            j = i*2+1;
        }
        return i>index;
    }


    void TimerManager::addTimer(int id, int timeout,const TimeoutCallBack &cb) {
        assert(id>0);
        size_t i;
        if(fd_pos_array_.count(id)==0){
            // 新结点，堆尾插入 ，调整堆
            i = time_array_.size();
            fd_pos_array_[id] = i;
            time_array_.push_back({id,Clock::now()+Ms(timeout),cb});
            siftup(i);
        }else{
//           该结点存在，调整堆
            i = fd_pos_array_[id];
            time_array_[i].expire = Clock ::now()+Ms (timeout);
            time_array_[i].cb = cb;
            if(!sifydown(i,time_array_.size())){
                siftup(i);
            }
        }
    }

    void TimerManager::work(int id) {
        if(time_array_.empty() || fd_pos_array_.count(id)==0){
            return;
        }
        size_t i = fd_pos_array_[id];
        TimeNode node = time_array_[i];
        node.cb();
        del(i);
    }

    void TimerManager::del(size_t index) {
        assert(!time_array_.empty() && index>=0 && index<time_array_.size());
        size_t i = index;
        size_t n = time_array_.size()-1;
        if(i<n){
            swapNode(i,n);
            if(!sifydown(i,n)){
                siftup(i);
            }
        }
        /*删除堆尾巴元素*/
        fd_pos_array_.erase(time_array_.back().id);
        time_array_.pop_back();
    }

    void TimerManager::update(int id, int timeout) {
        assert(!time_array_.empty() && fd_pos_array_.count(id)>0);
        time_array_[fd_pos_array_[id]].expire = Clock::now()+Ms(timeout);
        sifydown(fd_pos_array_[id],time_array_.size());
    }

    void TimerManager::handle_expired_event() {
        /*清除超时结点*/
        if(time_array_.empty()) return;
        while(!time_array_.empty()){
            TimeNode node = time_array_.front();
            if(std::chrono::duration_cast<Ms>(node.expire -Clock::now()).count()>0){
                break;
            }
            node.cb();
            pop();
        }
    }

    void TimerManager::pop() {
        assert(!time_array_.empty());
        del(0);
    }

    void TimerManager::clear() {
        time_array_.clear();
        fd_pos_array_.clear();
    }

    int TimerManager::getNextHandle() {
        handle_expired_event();
        size_t res = -1;
        if(!time_array_.empty()){
            res = std::chrono::duration_cast<Ms>(time_array_.front().expire-Clock::now()).count();
            if(res<0) res=0;
        }
        return res;
    }


}